package own.stu.jobgib.playown.juc.completeFuture;

import lombok.extern.slf4j.Slf4j;
import own.stu.jobgib.playown.juc.completeFuture.own.MyCompletableFuture;

import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;

@Slf4j
public class MyCompleteFutureTest {
    private String name;

    public static void main(String[] args) throws Exception {
//        ex();
//        ex2();

//        baisc();

        firstDep();
    }

    /**
     * pic/MyCompletableFuture.png
     * <p>
     * 零依赖：CompletableFuture的创建
     */
    private static void zeroDep() {

        //1、使用runAsync或supplyAsync发起异步调用
        MyCompletableFuture.supplyAsync(() -> "result1");

        //2、MyCompletableFuture.completedFuture()直接创建一个已完成状态的CompletableFuture
        MyCompletableFuture.completedFuture("result2");

        //3、先初始化一个未完成的CompletableFuture，然后通过complete()、completeExceptionally()，完成该CompletableFuture
        MyCompletableFuture<Object> future = new MyCompletableFuture<>();
        future.complete("result3");
    }

    /**
     * 3.2.2 一元依赖：依赖一个CF
     * <p>
     * 对于单个CompletableFuture的依赖可以通过thenApply、thenAccept、thenCompose等方法来实现
     */
    private static void firstDep() throws ExecutionException, InterruptedException {
        System.out.println(
                MyCompletableFuture.
                        supplyAsync(() -> "result1").
                        thenApply(result1 -> {
                            //result1为CF1的结果
                            //......
                            return "result3";
                        }).get());
    }

    /**
     * 二元依赖：依赖两个CF
     * <p>
     * 二元依赖可以通过thenCombine等回调来实现
     */
    private static void secDep() {
        MyCompletableFuture<String> cf1 = MyCompletableFuture.supplyAsync(() -> "result1");
        MyCompletableFuture<String> cf2 = MyCompletableFuture.completedFuture("result2");

        MyCompletableFuture<String> cf4 = cf1.thenCombine(cf2, (result1, result2) -> {
            //result1和result2分别为cf1和cf2的结果
            return "result4";
        });
    }

    /**
     * 多元依赖：依赖多个CF
     * <p>
     * 多元依赖可以通过allOf或anyOf方法来实现，区别是当需要多个依赖全部完成时使用allOf，当多个依赖中的任意一个完成即可时使用anyOf
     */
    private static void mulitDep() {

        MyCompletableFuture<String> cf3 = MyCompletableFuture.supplyAsync(() -> "result1");
        MyCompletableFuture<String> cf4 = MyCompletableFuture.completedFuture("result2");

        MyCompletableFuture<String> cf5 = new MyCompletableFuture<>();
        cf3.complete("result3");

        MyCompletableFuture<Void> cf6 = MyCompletableFuture.allOf(cf3, cf4, cf5);
        MyCompletableFuture<String> result = cf6.thenApply(v -> {
            //这里的join并不会阻塞，因为传给thenApply的函数是在CF3、CF4、CF5全部完成时，才会执行 。
            String result3 = cf3.join();
            String result4 = cf4.join();
            String result5 = cf5.join();
            //根据result3、result4、result5组装最终result;
            return "result";
        });
    }


    private static void ex2() {
        MyCompletableFuture<Integer> future = MyCompletableFuture.supplyAsync(() -> {
            System.out.println(" ----- do business");
            try {
                TimeUnit.MILLISECONDS.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
//            int i = 10 / 0;
            return 0;
        }).thenApply(result -> {
            System.out.println(result);
            int i = 10 / 0;
            return 2;
        }).exceptionally(err -> {
            log.error("Exception {}", err);
            return null;
        });

        future.join();
    }

    private static void ex() {
        MyCompletableFuture<Integer> future = MyCompletableFuture.supplyAsync(() -> {
            System.out.println(" ----- do business");
            try {
                TimeUnit.MILLISECONDS.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            int i = 10 / 0;
            return 0;
        }).exceptionally(err -> {
            log.error("Exception {}", err);
            return null;
        });

        future.join();
    }

    private static void baisc() {
        MyCompletableFuture.runAsync(() -> {
            System.out.println("1111111");
        });

        MyCompletableFuture.supplyAsync(() -> {
            System.out.println("xxxx");
            return 1001;
        }).thenAccept(res -> {
            System.out.println(res + " yyyyyyyy");
        });
        System.out.println("-----");
    }
}
